package wili.a;

import java.lang.reflect.Array;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * @author weilai2@163.com
 */
class AttValueFinder extends Obj9 {
	final Object[] roots;

	public AttValueFinder(Object... roots) {
		this.roots = roots;
	}

	static void log(String msg) {

		System.out.println(msg);
	}

	final Map<Object, Integer> skipMap = new HashMap<>();
	int foundTimes = 0;
	String findName;
	String findValue;

	public boolean find(String name, String value) {
		StringBuilder path = new StringBuilder();
		foundTimes = 0;
		try {
			this.findName = name;
			this.findValue = value;
			Object oneRoot = null;
			for (Object root : roots) {
				if (root == null)
					continue;
				oneRoot = root;
				String cname = root.getClass().getSimpleName();
				path.delete(0, path.length());
				path.append(name);
				if (find00(cname, root, path)) {
					continue;
				} else {
					continue;
				}

			}
			if (oneRoot == null)
				return false;
			if (foundTimes == 0) {
				log(" AttValueFinder.NotFound: " + name + "=" + value + "\n from: " + oneRoot.getClass());
				return false;
			}
			return true;
		} finally {
			skipMap.clear();
		}
	}

	static boolean isEq(String st, Object val) {
		if (st.equals(val))
			return true;
		if (st.equals(String.valueOf(val)))
			return true;
		return false;
	}

	@SuppressWarnings("all")
	boolean find00(final String curName, Object curValue, StringBuilder path) {
		if (curValue == null) {
			return false;
		}
		try {
			Class<?> cls = curValue.getClass();
			if (Coms5.isSimpleOrLangClass(cls)) {
				boolean print = false;
				if (this.findName.isEmpty() || curName.equals(this.findName)) {
					if (this.findValue.isEmpty() || isEq(findValue, curValue)) {
						++foundTimes;
						System.out.println("\n " + foundTimes + ", AttValueFinder.found: " + path + "=" + curValue);
						return true;
					}
				}
				return false;
			}
			long id = System.identityHashCode(curValue);
			Integer objId = skipMap.get(id);// 对象的hashCode或会变化，故用identityHashCode
			if (objId != null) {
				return false;
			}
			skipMap.put(id, objId = ++incID);
			int len = path == null ? -1 : path.length();
			if (curValue instanceof Collection) {
				Collection cc = (Collection) curValue;
				int ind = -1;
				for (Object ele : cc) {// 尝试遍历各子
					++ind;
					String name = "[" + ind + "]";
					path.append(name);
					if (find00(name, ele, path))
						++foundTimes;
					path.delete(len, path.length());
				}
			} else if (curValue instanceof Map) {
				Map<Object, Object> map = (Map) curValue;
				for (Map.Entry<Object, Object> ent : map.entrySet()) {
					String name = ent.getKey().toString();
					path.append("." + name);
					Object value = ent.getValue();
					if (find00(name, value, path)) {
						++foundTimes;
					}
					path.delete(len, path.length());
				}
			} else if (cls.isArray()) {
				if (Coms5.isSimpleOrLangClass(cls.getComponentType())) {
				} else {
					int aaLen = Array.getLength(curValue);
					for (int i = 0; i < aaLen; i++) {
						String name = "[" + i + "]";
						Object value = Array.get(curValue, i);
						path.append(name);
						if (find00(name, value, path))
							++foundTimes;
						path.delete(len, path.length());
					}
				}
			} else {
				Map<String, Object> map = Coms5.valueMapOfObject(curValue);
				String cname = curValue.getClass().getSimpleName();
				for (Map.Entry<String, Object> ent : map.entrySet()) {
					String name = String.valueOf(ent.getKey());
					path.append("." + name);
					Object value = ent.getValue();
					if (find00(name, value, path))
						++foundTimes;
					path.delete(len, path.length());
				}
			}
			return false;
		} catch (Throwable e) {
			e.printStackTrace();
			return foundTimes > 0;
		}
	}

	static void pause() {
	}
}
